#pragma once
#include <sys/socket.h>
#include <unistd.h>
#include <iostream>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include "Commn.hpp"
#include <cstdlib>
#include "Log.hpp"
#include "InetAddr.hpp"
#include <string>
#include <fcntl.h>
namespace SocketModule
{
    using namespace LogModule;
    class Socket;
    using SockPtr = std::shared_ptr<Socket>;
    // 模板方法模式
    class Socket
    {
    public:
        virtual ~Socket() {}
        // 一系列方法，有子类实现
        virtual bool sockerorDie() = 0;
        virtual bool bindorDie(int port) = 0;
        virtual bool listenorDie() = 0;
        virtual int accpetor(InetAddr* client_addr, int* aerrno) = 0;
        virtual void SetSockOpt() = 0;
        virtual int TcpRecv(std::string* out) = 0;
        virtual int TcpSend(std::string& in) = 0;
        virtual void Close() = 0;
        virtual int FD() = 0;
        virtual void SetNonBlock() = 0;
        // 创建Tcp的固定模式
        void BuildTcpserver(int port)
        {
            sockerorDie();
            SetSockOpt();
            bindorDie(port);
            listenorDie();
        }
    };

    class Tcpsocket : public Socket
    {
    public:
        Tcpsocket(int socketfd = gsocketfd)
            : _socketfd(socketfd)
        {
        }
        ~Tcpsocket() {}
        virtual void SetNonBlock() override
        {
            int fd = ::fcntl(_socketfd,F_GETFL);
            if (fd < 0)
            {
                perror("fcntl error");
                return ;
            }
            ::fcntl(_socketfd,F_SETFL,fd | O_NONBLOCK);
        }
        virtual bool sockerorDie() override
        {
            _socketfd = socket(AF_INET, SOCK_STREAM, 0);
            if (_socketfd < 0)
            {
                LOG(LogLevel::ERROR) << "socket create error";
                exit(SOCKET_ERROR);
            }
            SetNonBlock();
            LOG(LogLevel::INFO) << "socket create success, sockfd is : " << _socketfd;
            return true;
        }
        virtual void SetSockOpt()
        {
            int opt = 1;
            int n = ::setsockopt(_socketfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
            (void)n;
        }
        virtual bool bindorDie(int port) override
        {
            InetAddr local(port); //自动绑定服务端端口的信息
            int n = bind(_socketfd,local.NetAddr(),local.Len());
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "bind error";
                exit(BIND_ERROR);
            }
            LOG(LogLevel::INFO) << "bind success";
            return true;
        }

        virtual bool listenorDie()  override
        {
            int n1 = listen(_socketfd,BACKLOG);
            if (n1 < 0)
            {
                LOG(LogLevel::ERROR) << "listen error";
                exit(LISTEN_ERROR);
            }
            LOG(LogLevel::INFO) << "listen success";
            return true;
        }
        int accpetor(InetAddr* client_addr, int* aerrno) override
        {
            if (!client_addr) return -1;
            int socketfd = ::accept(_socketfd,client_addr->NetAddr(),client_addr->NetLen());
            if (socketfd < 0) 
            {
                *aerrno = errno;
                LOG(LogLevel::ERROR) << "accpet error ... Ignore";
                return -1;
            }
            client_addr->SetAddr();
            LOG(LogLevel::INFO) << "accpet success, file fd is : " << socketfd;
            return socketfd;
        }

        virtual int TcpRecv(std::string* out) override
        {
            char inbuffer[4096];
            int n = recv(_socketfd,inbuffer,sizeof(inbuffer)-1,0);
            inbuffer[n] = 0;
            *out = inbuffer;
            return n;
        }
        virtual int TcpSend(std::string& in) override
        {
            int n = send(_socketfd,in.c_str(),in.size(),0);
            return n;
        }
        virtual void Close() override
        {
            ::close(_socketfd);
        }
        virtual int FD() override { return _socketfd;} 
    private:
        int _socketfd;
    };
}